package advancedpart.assignmentA2;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import shared.*;

import advancedpart.assignmentA2.SearcherA2;
import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import writer.TestResult; // TestResult class for benchmarking
import writer.WriteExcel; // For writing benchmark to excel


@SuppressWarnings("unused")
public class BenchmarkA2 {

	/**
	 * This class runs a number of performance tests SearchCmd A2, advanced part
	 * 
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws FileNotFoundException, IOException {

		String inputFile = args[0];
		String outputFile = args[1];

		runBenchmark(inputFile, outputFile);

	}

	// Variables for measuring time end memory
	private static long t1,t2,m1,m2;
	private static int SLEEP_SIZE = 200;

	private static ArrayList<TestResult> listBenchmark = new ArrayList<TestResult>(); // results of test
	private static ArrayList<TestResult> singleBenchmark = new ArrayList<TestResult>();
	private static ArrayList<TestResult> doubleBenchmark = new ArrayList<TestResult>();
	private static ArrayList<TestResult> memoryBenchmark = new ArrayList<TestResult>();

	static final int NUMBER_OF_LIST_AND_MEMORY_TESTS = 10;
	static final int NUMBER_OF_SINGLEWORD_TESTS = 200;
	static final int NUMBER_OF_MOREWORDS_TESTS = 200;

	/**
	 * Runs performance test of hashMapFile and getUrls
	 * in each test loop the garbage collector is emptied
	 * 
	 * @param l - HTMLWordList[] to use in test
	 * @param inputFile, File to read in
	 * @param outputFile, target file for benchmarking
	 * @throws IOException 
	 * 
	 */
	private static void runBenchmark (String inputFile, String outputFile) throws IOException, FileNotFoundException{

		putOutTheGarbage(); // empty garbage collector before first test

		// Benchmark time of hashMap Creation
		// Benchmark memory use
		for (int i = 1 ; i <= NUMBER_OF_LIST_AND_MEMORY_TESTS ; i++) {

			m1 = getMemoryUse(); // Memory use before calling method
			t1 = System.nanoTime(); // setoff time
			try {

				HashMap<String, WordList> wordMap = SearcherA2.createWordMap(inputFile);

			} catch (IOException e) {
				e.printStackTrace();
			}

			t2 = System.nanoTime(); // end time
			m2 = getMemoryUse(); // Memory use after calling method

			// add result to ArrayList of results
			memoryBenchmark.add(new TestResult(i, m2-m1 ));
			listBenchmark.add(new TestResult(i, t2-t1 ));

			putOutTheGarbage(); // empty garbage collector before next iteration

		}

		putOutTheGarbage(); // empty garbage collector before next test

		HashMap<String, WordList> wordMap = SearcherA2.createWordMap(inputFile);

		System.out.println("Search for single word ");
		// Perform time measure 100 times
		for (int i = 1 ; i <= NUMBER_OF_SINGLEWORD_TESTS ; i++) {

			t1 = System.nanoTime(); // setoff time

			String tmp = SearcherA2.getUrlsForOneWord(wordMap, "home");
			tmp = SearcherA2.getUrlsForOneWord(wordMap, "aCompleteStrangeWord");

			t2 = System.nanoTime(); // end time

			// Add result to Arraylist 
			singleBenchmark.add(new TestResult(i, t2-t1 ));

			putOutTheGarbage(); // empty garbage collector before next iteration

		}


		System.out.println("Serach for two words:");
		// Perform time measure  NUMBER_OF_MOREWORDS_TESTS times
		for (int i = 1 ; i <= NUMBER_OF_MOREWORDS_TESTS ; i++) {

			t1 = System.nanoTime(); // setoff time

			String tmp = SearcherA2.getUrlsForTwoWords(wordMap, "home", "internet", SearchOperator.AND);
			tmp = SearcherA2.getUrlsForTwoWords(wordMap, "home", "internet", SearchOperator.OR);

			t2 = System.nanoTime(); // end time

			// Add result to Arraylist 
			doubleBenchmark.add(new TestResult(i, t2-t1 ));

			putOutTheGarbage(); // empty garbage collector before next iteration

		}


		// Create new Excel Workbook and write results
		WriteExcel testReport = new WriteExcel();
		File file = new File(outputFile + "V2.xls");

		WorkbookSettings wbSettings = new WorkbookSettings();
		wbSettings.setLocale(new Locale("en", "EN"));

		try {

			WritableWorkbook workbook = Workbook.createWorkbook(file, wbSettings);

			testReport.addSheet(workbook, "hashMap Benchmark", listBenchmark, "test no." , "Time in Nanosec");
			testReport.addSheet(workbook, "One word Benchmark", singleBenchmark, "test no." , "Time in Nanosec");
			testReport.addSheet(workbook, "Two words Benchmark", doubleBenchmark, "test no." , "Time in Nanosec");
			testReport.addSheet(workbook, "Memory Benchmark", memoryBenchmark, "n", "Bytes");
			workbook.write();
			workbook.close();

		} catch (IOException e1) {
			e1.printStackTrace();

		} catch (WriteException w1) {
			w1.printStackTrace();
		}

		System.out.println("Bencmark completed - saved to " + outputFile + ".xls");

	}

	private static long getMemoryUse() {

		putOutTheGarbage();
		long totalMemory = Runtime.getRuntime().totalMemory();
		putOutTheGarbage();
		long freeMemory = Runtime.getRuntime().freeMemory();

		return (totalMemory - freeMemory);
	}

	private static void putOutTheGarbage(){
		collectGarbage();
		collectGarbage();
	}

	private static void collectGarbage() {
		try {
			System.gc();
			Thread.currentThread();
			Thread.sleep(SLEEP_SIZE);
			System.runFinalization();
			Thread.sleep(SLEEP_SIZE);
		}

		catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}

}
